package ru.spb.osll.myfit.server.execute;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import ru.spb.osll.myfit.common.PageProgressCounts;
import ru.spb.osll.myfit.util.StringPrintWriter;
import fit.Counts;
import fit.Parse;

public class ProgressFixtureListenerProxy implements ProgressFixtureListener {
	private ClassLoader m_classLoader;
	private Object m_listener;
	
	public ProgressFixtureListenerProxy(ClassLoader classLoader, Object listener) {
		m_classLoader = classLoader;
		m_listener = listener;
	}

	@Override
	public void tableFinished(Parse table) {
	   try {
		   Method method = m_listener.getClass().getMethod("tableFinished", parseClass());
		   method.invoke(m_listener, convertParse(table));
	   } catch(Exception e) {
		   e.printStackTrace();
	   }
	}

	@Override
	public void tablesFinished(Counts counts) {
		   try {
			   Method method = m_listener.getClass().getMethod("tablesFinished",countsClass());
			   method.invoke(m_listener, convertCounts(counts));
		   } catch(Exception e) {
			   e.printStackTrace();
		   }	
	}

	@Override
	public void setCounts(Counts counts) {
		   try {
			   Method method = m_listener.getClass().getMethod("setCounts", countsClass());
			   method.invoke(m_listener, convertCounts(counts));
		   } catch(Exception e) {
			   e.printStackTrace();
		   }	
	}

	@Override
	public PageProgressCounts getCounts() {
		   try {
			   Method method = m_listener.getClass().getMethod("getCounts");
			   Object result = method.invoke(m_listener);
			   return convertProgressCounts(result);
		   } catch(Exception e) {
			   e.printStackTrace();
			   return new PageProgressCounts();
		   }	
	}

	@Override
	public void countTotalTablesQuantity(Parse tables) {
		   try {
			   Method method = m_listener.getClass().getMethod("countTotalTablesQuantity", parseClass());
			   method.invoke(m_listener, convertParse(tables));
		   } catch(Exception e) {
			   e.printStackTrace();
		   }
	}
	
	@SuppressWarnings("unchecked")
	protected Class<Parse> parseClass() throws Exception {
		return (Class<Parse>) m_classLoader.loadClass(Parse.class.getName());
	}
	
	@SuppressWarnings("unchecked")
	protected Class<Counts> countsClass() throws Exception {
		return (Class<Counts>) m_classLoader.loadClass(Counts.class.getName());
	}
	
	@SuppressWarnings("unchecked")
	protected Class<PageProgressCounts> progressCountsClass() throws Exception {
		return (Class<PageProgressCounts>) m_classLoader.loadClass(PageProgressCounts.class.getName());
	}
	
	protected Object convertParse(Parse parse) throws Exception {
		 StringPrintWriter writer = new StringPrintWriter();	
		 parse.print(writer);
		 String html = writer.toString();
		 Class<Parse> clazz = parseClass();
		 Constructor<Parse> constructor = clazz.getConstructor(String.class);
		 return constructor.newInstance(html);
	}
	
	protected Object convertCounts(Counts counts) throws Exception {
	 	 Class<Counts> clazz = countsClass();
		 Constructor<Counts> constructor = clazz.getConstructor(Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
		 return constructor.newInstance(counts.right, counts.wrong, counts.ignores, counts.exceptions);
	}
	
	protected PageProgressCounts convertProgressCounts(Object counts) throws Exception {
	 	int right = invokeGetter(counts, "getRight");
	 	int wrong = invokeGetter(counts, "getWrong");
	 	int ignores = invokeGetter(counts, "getIgnores");
	 	int exceptions = invokeGetter(counts, "getExceptions");
	 	int progressSegments = invokeGetter(counts, "getProgressSegments");
	 	int totalSegments = invokeGetter(counts, "getTotalSegments");
  	    return new PageProgressCounts(right, wrong, ignores, exceptions, progressSegments, totalSegments);
	}
	
	protected int invokeGetter(Object counts, String methodName) throws Exception {
		Method getter = counts.getClass().getMethod(methodName);
		Integer result = (Integer) getter.invoke(counts);
		return result.intValue();
	}
}
